#include <lua.h>
#include <lauxlib.h>
#include <string.h>
#include <time.h>
#include <stdint.h>

/*
** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
** compute its hash
*/
#if !defined(LUAI_HASHLIMIT)
#define LUAI_HASHLIMIT		5
#endif

static  unsigned int seed=0x1234ABCD;

static int lhash(lua_State *L){
	const char * str  = luaL_checkstring(L,1);
	unsigned int l = strlen(str);
	unsigned int h = seed ^ l;
	size_t step = (l >> LUAI_HASHLIMIT) + 1;
	for (; l >= step; l -= step)
		h ^= ((h<<5) + (h>>2) + (unsigned char)(str[l - 1]));
	lua_pushinteger(L,h);
	return 1;
}

static int lmurmurhash (lua_State *L){
	const char * key  = luaL_checkstring(L,1);
	uint32_t len=strlen(key);
  	uint32_t c1 = 0xcc9e2d51;
  	uint32_t c2 = 0x1b873593;
  	uint32_t r1 = 15;
  	uint32_t r2 = 13;
  	uint32_t m = 5;
  	uint32_t n = 0xe6546b64;
  	uint32_t h = 0;
  	uint32_t k = 0;
  	uint8_t *d = (uint8_t *) key; // 32 bit extract from `key'
  	const uint32_t *chunks = NULL;
  	const uint8_t *tail = NULL; // tail - last 8 bytes
  	int i = 0;
  	int l = len / 4; // chunk length

  	h = seed;

  	chunks = (const uint32_t *) (d + l * 4); // body
  	tail = (const uint8_t *) (d + l * 4); // last 8 byte chunk of `key'

  	// for each 4 byte chunk of `key'
  	for (i = -l; i != 0; ++i) {
    	// next 4 byte chunk of `key'
    	k = chunks[i];
    	// encode next 4 byte chunk of `key'
    	k *= c1;
    	k = (k << r1) | (k >> (32 - r1));
    	k *= c2;

    	// append to hash
    	h ^= k;
    	h = (h << r2) | (h >> (32 - r2));
    	h = h * m + n;
  	}

  	k = 0;

  	// remainder
  	switch (len & 3) { // `len % 4'
   		case 3: k ^= (tail[2] << 16);
    	case 2: k ^= (tail[1] << 8);

    	case 1:
      		k ^= tail[0];
      		k *= c1;
      		k = (k << r1) | (k >> (32 - r1));
      		k *= c2;
      		h ^= k;
  	}

  	h ^= len;

  	h ^= (h >> 16);
  	h *= 0x85ebca6b;
  	h ^= (h >> 13);
  	h *= 0xc2b2ae35;
  	h ^= (h >> 16);

	lua_pushinteger(L,h);
  	return 1;
}

static int lcoredump (lua_State *L){
	strcpy(NULL,"asasdads");
	return 0;
}
int luaopen_algorithm_c(lua_State *L){
	luaL_Reg reg[] = {
		{"hash",lhash},
		{"murmur_hash",lmurmurhash},
		{"coredump",lcoredump},
		{NULL,NULL}
	};

	//seed=time(NULL);
	luaL_checkversion(L);
	luaL_newlib(L, reg);
	return 1;
}
